<?php

namespace zhuli\core;

/**
 * 依赖注入容器接口
 *
 * 这个接口定义了依赖注入容器该实现的方法
 */
interface DiInterface
{
    /**
     * 设置依赖关系
     *
     * 第一个参数可以是完全限定类名，也可以是接口。
     * 如果是类名那么第二个参数就必须是数组，数组是键值对的形式，键是参数的名称，值就是要传递给构造函数的值。
     * 如果是接口，那么第二个参数就是该接口对应的实现类。
     *
     * @param string $class 完全限定类名|接口
     * @param array|string $args 如果是数组将传递给第一个参数的类的构造方法；如果第一个参数是接口，那么这个参数就是相应的实现类
     * @return self 为了实现链式调用，请返回实现类的实例，即`$this`
     */
    public function set($class, $args = []);

    /**
     * 设置一个单例
     *
     * @param string $class 完全限定类名，注意这个不能传递接口
     * @param array $args
     * @return self
     */
    public function setSingleton($class, $args = []);

    /**
     * 获取给定类名的实例
     *
     * 当获取A时，发现A依赖了B，如果B的构造函数比较复杂，容器不能自动解决该传递的参数时，就要求调用者事先调用DiInterface::set()注册好依赖关系。
     *
     * @param string $class 要获取的实例的完全限定类名
     * @param array $args 传递给这个类的构造函数的参数，键值对形式，键是参数的名称，值就是参数的值
     * @return $class 返回的是要获取的实例
     */
    public function get($class, $args = []);
}


// class DependencyInjection implements DiInterface
// {

//     private $params = [];
//     private $defination = [];//类是否已经定义
//     public function set($class, $args = [])
//     {
       
//         $this->params[$class] = $args;
//         $this->defination[$class] = $class;
//     }

//     public function get($class, $args = [])
//     {
//         if (isset($this->defination[$class])) {
//            $reflect = new ReflectionClass($class);
//            return $reflect->newInstance();
//         } else {
//             $this->set($class, $args);
//         }

//     }
// }

//     // set是让开发者定义依赖关系的

    // A类依赖了B类，当调用DiInterface::get('A')的时候，容器必然会遇到一个尴尬的问题，
    // 容器会想：“new B的时候，需要传递姓名，性别，年龄这三个参数，可是我怎么知道这些参数？”。

    // 所以开发者必须先调用DiInterface::set('B',['name'=>'zhuli','gender'=>'女','age'=>18]);
    // 然后才能调用DiInterface::get('A')

    // set('zhuli\test\User',['name'=>'zhuli','gender'=>'女','age'=>18]);
    // set('zhuli\test\ConfigInterface','zhuli\test\Config');

    // 目前就是这两种传参方式，这些是定义信息，把它们保存起来，
    // 当调用get的时候，碰到了'zhuli\test\User'要实例化时，就用这个已经定义的信息